package org.example.day07;

import java.util.ArrayList;
import java.util.List;

/**
 * 第三章节3.1.7: 使用wait/notify的业务demo
 *      注意：notify后并没有释放锁，而是知道同步代码块执行结束，被唤醒的线程没有立即开始执行，而是等notify的线程释放了锁，才开始执行。
 */
public class MyThread6 {
    volatile private List list = new ArrayList<>();

    public void add() {
        list.add("anything");
    }

    public int size() {
        return list.size();
    }

    public static void main(String[] args) throws InterruptedException {
        MyService service = new MyService();
        Thread6A ta = new Thread6A(service);
        ta.start();
        Thread.sleep(5000);
        Thread6B tb = new Thread6B(service);
        tb.start();
    }
}

class MyService{
    private Object lock = new Object();
    private MyThread6 m6 = new MyThread6();
    public void waitMethod(){
        try {
            synchronized (lock){
                if(m6.size() != 5){
                    System.out.println("begin wait = " + System.currentTimeMillis() + " ThreadName = " + Thread.currentThread().getName());
                    lock.wait(); //释放锁
                    System.out.println("end wait = " + System.currentTimeMillis() + " ThreadName = " + Thread.currentThread().getName());
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public void notifyMethod(){
        try {
            synchronized (lock){
                System.out.println("begin notify = " + System.currentTimeMillis() + " ThreadName = " + Thread.currentThread().getName());
                for (int i = 0; i < 10; i++) {
                    m6.add();
                    if(m6.size() == 5){
                        lock.notify();
                        System.out.println("唤醒后并没有释放锁，被唤醒的线程也没有立即执行");
                    }
                    System.out.println("add次数 = " + (i+1));
                    Thread.sleep(1000);
                }
                System.out.println("end notify = " + System.currentTimeMillis() + " ThreadName = " + Thread.currentThread().getName());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class Thread6A extends Thread{
    private MyService service;

    public Thread6A(MyService service) {
        this.service = service;
    }

    @Override
    public void run() {
        service.waitMethod();
    }
}

class Thread6B extends Thread{
    private MyService service;

    public Thread6B(MyService service) {
        this.service = service;
    }

    @Override
    public void run() {
        service.notifyMethod();
    }
}